/**
 * @description          表格排序实现，工具包js使用的是闭包实现
 * table排序的原理：取出所有排序列的值并存放在数组中(并且各列对应行对象也存放到一个数组中)，
 * 然后对排序列的值数组排序(并对行对象数组排序)
 * 说明：
 * (1)把需要排序的行放到tbody中，程序会直接取tbody的rows作为排序行；
 * (2)把排序行放到一个数组中，按需求对数组进行排序（这里没有使用数组的sort、reverse方法，而是采用冒泡算法）
 * @original author      Blog:http://www.cnblogs.com/know/archive/2011/10/29/2228682.html
 * @modify author        Xiaopeng
 * @create date          2011-10-28
 * @modify date          2015-01-04
 * @modify description   
 * (1)修改了对汉字排序有误的问题，可以实现字母汉字混排，其实现原理是：将汉字转换为全拼，统一按字母排序；
 * (2)添加排序列鼠标点击，提示正序、逆序排序图标
 **/
 (function () {
     //#region 全局变量
     //初始化配置对象
     var _initConfig = null;
     var _tableObj = null, _tbodyObj = null, _tBodyIndex = 0;
     //存放当前各排序方式下的(有序)行数组的对象——仅在IsLazyMode=true，此变量有用
     var _trJqObjArray_Obj = null;
     //#endregion
 
     //#region 内部方法
     /**
      * 获得排序列值数组的方法
      * @private
      * @param trJqObjArr：(外部传入)存放排序行的数组，tdIndex：排序列的索引，td_valAttr：排序列的取值属性，td_dataType：排序列的值类型
      **/
     function GetOrderTdValueArray(trJqObjArr, tdIndex, td_valAttr, td_dataType) {
         var tdOrderValArr = new Array();
         var trObj, tdObj, tdVal;
         _tbodyObj.find("tr").each(function (trIndex, trItem) {
             trObj = $(trItem);
             trJqObjArr.push(trObj);
 
             tdObj = trObj.find("td")[tdIndex];
             tdObj = $(tdObj);
             tdVal = td_valAttr ? tdObj.attr(td_valAttr) : tdObj.text();
             tdVal = GetValue(tdVal, td_dataType);
             tdOrderValArr.push(tdVal);
         });
         return tdOrderValArr;
     }
 
     /**
      * 返回jQuery对象的方法
      * @private
      **/
     function GetJqObj(id) {
         return "string" == typeof (id) ? $("#" + id) : $(id);
     };
 
     /**
     * 排序方法，考虑一般要排序的表格数据量都不大，其中的数组排序使用的是冒泡排序算法
     * 把要排序列的对应的行对象只一次遍历，并将排序后的行对象数组保存在全局对象中，
     * 下次排序时直接通过tdIndex(排序列的索引)取出对应的行对象数组,并将数组反转，
     * 即可实现排序的效果，可以在一定程度上提高代码执行效率(性能)
     * @private
     * @param tdIndex：排序列的索引,options：排序列的规则配置对象
     **/
     function Sort(tdIndex, options) {
         var trJqObjArr = null;
         if (_initConfig.IsLazyMode) {
             !_trJqObjArray_Obj && (_trJqObjArray_Obj = {});
             trJqObjArr = _trJqObjArray_Obj[tdIndex];
         }
         var isExist_trJqObjArr = true;
         if (!trJqObjArr) {
             isExist_trJqObjArr = false;
             trJqObjArr = new Array();
             var tdOrderValArr = GetOrderTdValueArray(trJqObjArr, tdIndex, options.ValAttr, options.DataType);
             var sort_len = tdOrderValArr.length - 1;
             var isExchanged = false, compareRes;
             for (var i = 0; i < sort_len; i++) {
                 isExchanged = false;
                 for (var j = sort_len; j > i; j--) {
                     compareRes = options.Desc ? (tdOrderValArr[j] > tdOrderValArr[j - 1]) : (tdOrderValArr[j] < tdOrderValArr[j - 1]);
                     if (compareRes) {
                         ExchangeArray(tdOrderValArr, j);
                         //交换行对象在数组中的顺序
                         ExchangeArray(trJqObjArr, j);
                         isExchanged = true;
                     }
                 }
                 //一遍比较过后如果没有进行交换则退出循环 
                 if (!isExchanged)
                     break;
             }
             _initConfig.IsLazyMode && (_trJqObjArray_Obj[tdIndex] = trJqObjArr);
         }
 
         if (trJqObjArr) {
             if (options.Toggle) {
                 _initConfig.IsLazyMode && isExist_trJqObjArr && trJqObjArr.reverse();
                 options.Desc = !options.Desc;
             }
             ShowTable(trJqObjArr);
         }
     }
 
     /**
      * 显示排序后的表格
      * @private
      * @param trJqObjArr：排序后的tr对象数组
      **/
     function ShowTable(trJqObjArr) {
    	 //用一个文档碎片document.createDocumentFragment()保存排好序的行，大量dom操作时使用文档碎片会更有效率
//    	 var fragment = document.createDocumentFragment();  
         for (var n = 0, len = trJqObjArr.length; n < len; n++) {
//        	 fragment.appendChild((trJqObjArr[n])[0]);  //将JQuery对象转换为DOM对象，并添加到文档中
             _tbodyObj.append(trJqObjArr[n]);
             $.isFunction(_initConfig.OnShow) && (_initConfig.OnShow(n, trJqObjArr[n], _tbodyObj));
         }
//         _tbodyObj.append(fragment);  
     }
 
     /**
      * 交换数组中项的方法
      * @private
      * @param array：数组，j：交换数组项的尾项索引
      **/
     function ExchangeArray(array, j) {
         var temp = array[j];
         array[j] = array[j - 1];
         array[j - 1] = temp;
     }
 
     /**
      * 添加排序方式(规则)的方法
      * @private
      * @param tdVal：排序列的值，td_dataType：排序列的值类型
      **/
     function GetValue(tdVal, td_dataType) {
         switch (td_dataType) {
             case "int":
            	 return parseInt(tdVal, 10) || 0;
             case "float":
                 return parseFloat(tdVal, 10) || 0;
             case "date":
                 return DateUtils.parseDate(tdVal) || 0;
             case "boolean":
            	 return value === true || String(value).toLowerCase() == "true" ? 1 : 0;
             case "string":
             default:
                 {
                     var tdVal = tdVal.toString() || "";
                     //如果值不为空，获得值是汉字的全拼
                     if (tdVal) {
                         tdVal = ZhCN_Pinyin.GetQP(tdVal);
                         tdVal = tdVal.toLowerCase();
                     }
                     return tdVal;
                 }
         }
     }
     
     /**
      * 这里用作样式设置
      */
     function Each(list, fun){
    	 for (var i = 0, len = list.length; i < len; i++) { fun(list[i], i); }
     }
 
     /**
      * 添加排序方式(规则)项的方法
      * @private
      * @param obj：排序触发(标签)的对象或id，index：要排序列所在的列索引，options：排序规则设置对象(如:DataType...)
      **/
     function SetOrderItem(obj, index, options) {
         var orderSettings = {
        	 Attri: "innerHTML", //获取数据的属性
             ValAttr: false, //排序列的取值属性,默认为：innerText
             DataType: "string", //排序列的值类型(可取值：int|float|date|string)
             OnClick: null, //(点击)排序时触发的方法
             Desc: true, //(是否是降序)排序方式，默认为：降序
             Toggle: true, //切换排序方式
             DefaultOrder: false, //是否是默认的排序方式
             onSort: function(){} //排序时执行，这里用于设置样式
         };
         $.extend(orderSettings, options);
         orderSettings.DataType = orderSettings.DataType.toLowerCase();
         //获取排序列对象
         obj = GetJqObj(obj);
         //_arr是记录排序项目（这里主要用来设置样式）
         !SetOrderItem._arr  &&  (SetOrderItem._arr = []); SetOrderItem._arr.push(obj);
         orderSettings.onSort = function() {
        	 //设置样式
        	 Each(SetOrderItem._arr, function(o){ obj.attr("class", ""); });
        	 orderSettings.Desc ? obj.attr("class", "up") : obj.attr("class", "down");
         }
         //绑定触发排序的事件
         obj.bind("click", function () {
             Sort(index, orderSettings);
             //执行样式设置
             orderSettings.onSort();
             //$.isFunction测试对象是否为函数
             $.isFunction(orderSettings.OnClick) && orderSettings.OnClick();
         });
         orderSettings.DefaultOrder && Sort(index, orderSettings);
     }
     //#endregion
 
     //#region 对外公开
     var _api = {
         Init: function (obj, tBodyIndex, options) {
             /// <summary>初始化方法</summary>
             /// <param name="obj" type="Object">要排序table的id或对象</param>
             /// <param name="tBodyIndex" type="int">要排序的数据行所在的tbody标签的索引</param>
             /// <param name="options" type="Object">初始化配置对象,{IsLazyMode:是否是懒惰模式,OnShow: 排序后表格显示时的方法}</param>
             if (obj == null || typeof (obj) == undefined) {
                 alert("TableSort初始化参数为空或有误！");
                 return;
             }
             if (typeof (ZhCN_Pinyin) == undefined) {
                 alert("获得汉字首拼的'ZhCN_Pinyin'对象不存在！");
                 return;
             }
             _tableObj = GetJqObj(obj);
             _tBodyIndex = tBodyIndex || 0;
             _tbodyObj = _tableObj.find("tbody:eq(" + _tBodyIndex + ")");
             options = options || {};
             _initConfig = {
            	 //IsLazyMode=true,适用于当前要排序的表格是不变的，即不会有ajax的增删改行的操作
            	 //IsLazyMode=false, 即适用于当前要排序的表格会改变，如有ajax的增删改行的操作的情况
                 IsLazyMode: true, //是否是懒惰模式，默认为:true
                 OnShow: null  //排序后表格显示时的方法,params:trIndex,trJqObj,tbodyObj
             };
             //合并对象，利用自定义配置初始化排序参数
             $.extend(_initConfig, options);
             _trJqObjArray_Obj = null;
         },
         SetOrder: function (obj, index, options) {
             /// <summary>设置排序规则的方法</summary>
             /// <param name="obj" type="Object">排序触发(标签)的对象或id</param>
             /// <param name="index" type="int">要排序列所在的列索引</param>
             /// <param name="options" type="Object">排序规则设置对象(如:DataType...)</param>
             if (_tableObj == null) {
                 alert("_tableObj尚未初始化！");
                 return;
             }
             SetOrderItem(obj, index, options);
         }
     };
     window.TableSortOper = _api;
     //#endregion
 })();